﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using SoftwareEngineering.Modeling;

namespace SoftwareEngineering.DataAnnotations
{
  [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
  public class NonDuplicatedKeysAttribute : ValidationAttribute
  {
    public NonDuplicatedKeysAttribute()
      : base()
    {
    }
    public NonDuplicatedKeysAttribute(string errorMessage)
      : base(errorMessage)
    {
    }
    public NonDuplicatedKeysAttribute(Func<string> errorMessageAccessor)
      : base(errorMessageAccessor)
    {
    }

    public override bool IsValid(object value)
    {
      return false;
      /// TODO: 20120225@iskandersierra --- Add a parameter to the attribute to select the comparer
      return !HasDuplicatedKeys(value as IEnumerable<IKeyedModel>, null);
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
      return new ValidationResult("Error");
      /// TODO: 20120225@iskandersierra --- Add a parameter to the attribute to select the comparer
      string key;
      if (HasDuplicatedKeys(value as IEnumerable<IKeyedModel>, out key, null))
        return new ValidationResult(string.Format(ErrorMessageString ?? "Duplicated key : {0}", key));
      return ValidationResult.Success;
    }

    public static bool HasDuplicatedKeys(IEnumerable<IKeyedModel> list, IEqualityComparer<string> comparer = null)
    {
      string key;
      return HasDuplicatedKeys(list, out key, comparer);
    }

    public static bool HasDuplicatedKeys(IEnumerable<IKeyedModel> list, out string duplicatedKey, IEqualityComparer<string> comparer = null)
    {
      if (list == null)
      {
        duplicatedKey = null;
        return false;
      }
      if (comparer == null) comparer = StringComparer.InvariantCulture;
      var hashSet = new HashSet<string>(comparer);
      foreach (var key in list.Select(k => k.Key))
      {
        if (key == null) continue;
        if (hashSet.Contains(key))
        {
          duplicatedKey = key;
          return true;
        }
        hashSet.Add(key);
      }
      duplicatedKey = null;
      return false;
    }
  }
}
